<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>不可实例的类型：接口</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.76.1">
<link rel="home" href="index.html" title="GObject 参考手册">
<link rel="up" href="chapter-gtype.html" title="GLib动态类型系统">
<link rel="prev" href="gtype-instantiable-classed.html" title="可实例化的类型：object">
<link rel="next" href="chapter-gobject.html" title="The GObject base class">
<meta name="generator" content="GTK-Doc V1.17 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
<td><a accesskey="p" href="gtype-instantiable-classed.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
<td><a accesskey="u" href="chapter-gtype.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
<th width="100%" align="center">GObject 参考手册</th>
<td><a accesskey="n" href="chapter-gobject.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
</tr></table>
<div class="sect1">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="gtype-non-instantiable-classed"></a>不可实例的类型：接口</h2></div></div></div>
<p>GType's interfaces are very similar to Java's interfaces. They allow GType的接口（Interface）与Java的接口非常类似。 它允许描述一个通用的API，使得多个类可以粘合在一起。 想像一下，Hi-Fi音响设备中的暂停和播放按钮──这可以被视做一个回放接口。 如果你知道你要做什么，你可以用来这个接口来控制你的CD机，MP3或其他使用相同符号的东西。 要声明一个接口，你需要注册一个从<a class="link" href="gobject-Type-Information.html#GTypeInterface" title="struct GTypeInterface"><span class="type">GTypeInterface</span></a> 继承的不可实例的类型。 下面的代码声明了这样的一个接口： </p>
<pre class="programlisting">
#define MAMAN_TYPE_IBAZ                (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_IBAZ, MamanIbaz))
#define MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_IBAZ))
#define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_TYPE_IBAZ, MamanIbazInterface))

typedef struct _MamanIbaz MamanIbaz; /* dummy object */
typedef struct _MamanIbazInterface MamanIbazInterface;

struct _MamanIbazInterface {
  GTypeInterface parent;

  void (*do_action) (MamanIbaz *self);
};

GType maman_ibaz_get_type (void);

void maman_ibaz_do_action (MamanIbaz *self);
</pre>
<p> 这里用非常简单的方法来实现<code class="function">maman_ibaz_do_action</code>这个接口函数： </p>
<pre class="programlisting">
void maman_ibaz_do_action (MamanIbaz *self)
{
  MAMAN_IBAZ_GET_INTERFACE (self)-&gt;do_action (self);
}
</pre>
<p><code class="function">maman_ibaz_get_type</code> 注册了一个从G_TYPE_INTERFACE继承的名为<span class="emphasis"><em>MamanIBaz</em></span>的类型。 在继承树中，所有的接口必须是G_TYPE_INTERFACE的子类。</p>
<p>一个接口只有一个包含<a class="link" href="gobject-Type-Information.html#GTypeInterface" title="struct GTypeInterface"><span class="type">GTypeInterface</span></a>的结构来定义。 接口的结构应该要包含一个函数指针指向这个接口的方法。 用类似于<code class="function">maman_ibaz_do_action</code>的方法在每个接口方法中定义帮助函数， 可以使得我们直接调用接口方法，这是一个良好的风格。</p>
<p>一旦一个接口的类型被注册后，你必须来实现这个接口。 其中，命名为<code class="function">maman_baz_get_type</code> 注册一个名为<span class="type">MamanIBaz</span>的由<a class="link" href="gobject-The-Base-Object-Type.html#GObject" title="struct GObject"><span class="type">GObject</span></a>继承来的新的GType， 并在接口Interface中实现。 </p>
<pre class="programlisting">
static void maman_baz_do_action (MamanIbaz *self)
{
  g_print ("Baz implementation of IBaz interface Action.\n");
}


static void
baz_interface_init (gpointer         g_iface,
                    gpointer         iface_data)
{
  MamanIbazInterface *iface = (MamanIbazInterface *)g_iface;
  iface-&gt;do_action = maman_baz_do_action;
}

GType 
maman_baz_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBazInterface),
      NULL,   /* base_init */
      NULL,   /* base_finalize */
      NULL,   /* class_init */
      NULL,   /* class_finalize */
      NULL,   /* class_data */
      sizeof (MamanBaz),
      0,      /* n_preallocs */
      NULL    /* instance_init */
    };
    static const GInterfaceInfo ibaz_info = {
      (GInterfaceInitFunc) baz_interface_init,    /* interface_init */
      NULL,               /* interface_finalize */
      NULL          /* interface_data */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBazType",
                                   &amp;info, 0);
    g_type_add_interface_static (type,
                                 MAMAN_TYPE_IBAZ,
                                 &amp;ibaz_info);
  }
  return type;
}
</pre>
<p><code class="function"><a class="link" href="gobject-Type-Information.html#g-type-add-interface-static" title="g_type_add_interface_static ()">g_type_add_interface_static</a></code> 记录了在类型系统中如 <span class="type">FooInterface</span>来实现的接口（<code class="function">foo_interface_get_type</code>返回<span class="type">FooInterface</span>的类型）， <a class="link" href="gobject-Type-Information.html#GInterfaceInfo" title="struct GInterfaceInfo"><span class="type">GInterfaceInfo</span></a>保存着关于接口实现的信息： </p>
<pre class="programlisting">
struct _GInterfaceInfo
{
  GInterfaceInitFunc     interface_init;
  GInterfaceFinalizeFunc interface_finalize;
  gpointer               interface_data;
};
</pre>
<p>如果没有特殊的需求，你可以直接使用<code class="function">G_DEFINE_INTERFACE</code>这个宏： </p>
<pre class="programlisting">
G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT)
</pre>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="gtype-non-instantiable-classed-init"></a>接口初始化</h3></div></div></div>
<p>
            When an instantiable classed type which registered an interface 
            implementation is created for the first time, its class structure 
            is initialized following the process
            described in <a class="xref" href="gtype-instantiable-classed.html" title="可实例化的类型：object">the section called “可实例化的类型：object”</a>. 
            After that, the interface implementations associated with
            the type are initialized.
          </p>
<p>
            First a memory buffer is allocated to hold the interface structure. The parent's
            interface structure is then copied over to the new interface structure (the parent
            interface is already initialized at that point). If there is no parent interface,
            the interface structure is initialized with zeros. The g_type and the g_instance_type
            fields are then initialized: g_type is set to the type of the most-derived interface
            and g_instance_type is set to the type of the most derived type which implements 
            this interface.
          </p>
<p>
            Finally, the interface' most-derived <code class="function">base_init</code> function and then 
            the implementation's <code class="function">interface_init</code>
            function are invoked. It is important to understand that if there are multiple 
            implementations of an interface the <code class="function">base_init</code> and 
            <code class="function">interface_init</code> functions will be
            invoked once for each implementation initialized.
          </p>
<p>
            It is thus common for base_init functions to hold a local static boolean variable
            which makes sure that the interface type is initialized only once even if there are 
            multiple implementations of the interface:
</p>
<pre class="programlisting">
static void
maman_ibaz_base_init (gpointer g_iface)
{
  static gboolean initialized = FALSE;

  if (!initialized) {
    /* create interface signals here. */
    initialized = TRUE;
  }
}
</pre>
<p>
          </p>
<p>
          If you have found the stuff about interface hairy, you are right: it is hairy but
          there is not much I can do about it. What I can do is summarize what you need to know
          about interfaces:          
        </p>
<p>
            The above process can be summarized as follows:
          </p>
<div class="table">
<a name="ginterface-init-table"></a><p class="title"><b>Table 2. 接口初始化</b></p>
<div class="table-contents"><table summary="接口初始化" border="1">
<colgroup>
<col align="left">
<col align="left">
<col align="left">
</colgroup>
<thead><tr>
<th align="left">Invocation time</th>
<th align="left">Function Invoked</th>
<th align="left">Function's parameters</th>
<th>Remark</th>
</tr></thead>
<tbody>
<tr>
<td rowspan="2" align="left">First call to <code class="function"><a class="link" href="gobject-Type-Information.html#g-type-create-instance" title="g_type_create_instance ()">g_type_create_instance</a></code> for type
                    implementing interface
                   </td>
<td align="left">interface' base_init function</td>
<td align="left">On interface' vtable</td>
<td>Register interface' signals here (use a local static 
                    boolean variable as described above to make sure not to register them
                    twice.).</td>
</tr>
<tr>
<td align="left">interface' interface_init function</td>
<td align="left">On interface' vtable</td>
<td>
                    Initialize interface' implementation. That is, initialize the interface 
                    method pointers in the interface structure to the function's implementation.
                  </td>
</tr>
</tbody>
</table></div>
</div>
<p><br class="table-break">
          It is highly unlikely (i.e. I do not know of <span class="emphasis"><em>anyone</em></span> who actually 
          used it) you will ever need other more fancy things such as the ones described in the
          following section (<a class="xref" href="gtype-non-instantiable-classed.html#gtype-non-instantiable-classed-dest" title="Interface Destruction">the section called “Interface Destruction”</a>).
        </p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="gtype-non-instantiable-classed-dest"></a>Interface Destruction</h3></div></div></div>
<p>
            When the last instance of an instantiable type which registered 
            an interface implementation is destroyed, the interface's 
            implementations associated to the type are destroyed.
          </p>
<p>
            To destroy an interface implementation, GType first calls the 
            implementation's <code class="function">interface_finalize</code> function 
            and then the interface's most-derived 
            <code class="function">base_finalize</code> function.
          </p>
<p>
            Again, it is important to understand, as in 
            <a class="xref" href="gtype-non-instantiable-classed.html#gtype-non-instantiable-classed-init" title="接口初始化">the section called “接口初始化”</a>,
              that both <code class="function">interface_finalize</code> and <code class="function">base_finalize</code>
              are invoked exactly once for the destruction of each implementation of an interface. Thus,
              if you were to use one of these functions, you would need to use a static integer variable
              which would hold the number of instances of implementations of an interface such that
              the interface's class is destroyed only once (when the integer variable reaches zero).
          </p>
<p>
          The above process can be summarized as follows:
          </p>
<div class="table">
<a name="ginterface-fini-table"></a><p class="title"><b>Table 3. Interface Finalization</b></p>
<div class="table-contents"><table summary="Interface Finalization" border="1">
<colgroup>
<col align="left">
<col align="left">
<col align="left">
</colgroup>
<thead><tr>
<th align="left">Invocation time</th>
<th align="left">Function Invoked</th>
<th align="left">Function's parameters</th>
</tr></thead>
<tbody>
<tr>
<td rowspan="2" align="left">Last call to <code class="function"><a class="link" href="gobject-Type-Information.html#g-type-free-instance" title="g_type_free_instance ()">g_type_free_instance</a></code> for type
                    implementing interface
                   </td>
<td align="left">interface' interface_finalize function</td>
<td align="left">On interface' vtable</td>
</tr>
<tr>
<td align="left">interface' base_finalize function</td>
<td align="left">On interface' vtable</td>
</tr>
</tbody>
</table></div>
</div>
<p><br class="table-break">
        </p>
</div>
</div>
<div class="footer">
<hr>
          Generated by GTK-Doc V1.17</div>
</body>
</html>